package com.ethink.platform.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import com.ethink.framework.common.constant.CommonRespCode;
import com.ethink.framework.common.exception.BusinessException;
import com.ethink.id.generator.IdGenerator;
import com.ethink.mdm.api.component.MdmComponent;
import com.ethink.mdm.api.info.CurrencyInfo;
import com.ethink.mdm.api.info.MateSkuInfo;
import com.ethink.order.api.SaleOrderFacade;
import com.ethink.order.api.TocSaleImportJobLogFacade;
import com.ethink.order.api.constant.OrderRespCode;
import com.ethink.order.api.enums.SaleOrderOrderStatusEnum;
import com.ethink.order.api.enums.SaleOrderOrderTypeEnum;
import com.ethink.order.api.info.*;
import com.ethink.order.api.model.SaleDetailOrderModel;
import com.ethink.order.api.model.SaleExcelModel;
import com.ethink.order.api.request.SaleOrderAdd2Request;
import com.ethink.order.api.request.TocSaleImportJobLogAddRequest;
import com.ethink.order.api.utils.EthinkStrUtil;
import com.ethink.platform.controller.order.info.SaleOrderImportInfo;
import com.ethink.warehouse.api.LogisticsTraceApplyOrderFacade;
import com.ethink.warehouse.api.MateInventoryFacade;
import com.ethink.warehouse.api.SubWarehouseFacade;
import com.ethink.warehouse.api.enums.InventoryTypeEnum;
import com.ethink.warehouse.api.enums.LogisticsTraceDetailOrderTypeEnum;
import com.ethink.warehouse.api.enums.MateInventoryOrderBizTypeEnum;
import com.ethink.warehouse.api.enums.SubjectEnum;
import com.ethink.warehouse.api.info.*;
import com.ethink.warehouse.api.request.LogisticsTraceApplyAddRequest;
import com.ethink.warehouse.api.request.MateInventoryLockLogAddRequest;
import com.ethink.warehouse.api.request.MateInventoryOutRequest;
import com.ethink.warehouse.api.request.MateInventoryQueryKeyInfo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author default
 * @version 1.0.0
 * @ClassName SaleOrderManager.java
 * @Description
 * @createTime 2022年11月22日 15:36:00
 */
@Component
@Slf4j
public class SaleOrderManager {

    @Autowired
    private ExcelImportManager excelImportManager;

    @Autowired
    private MateInventoryFacade mateInventoryFacade;

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private SaleOrderFacade saleOrderFacade;

    @Autowired
    private MdmComponent mdmComponent;

    @Autowired
    private SubWarehouseFacade subWarehouseFacade;

    @Autowired
    private LogisticsTraceApplyOrderFacade logisticsTraceApplyOrderFacade;

    @Autowired
    private TocSaleImportJobLogFacade tocSaleImportJobLogFacade;


    private static Map<String, String> shopChannelMap = new HashMap<>();

    static {
//        海蜜淘海外专营店  拼多多 0004，shopId：1242087450428572032
//        意欣美妆海外专营店 拼多多 0025，shopId：1549253799779173120
//        海蜜淘海外旗舰店 抖音 0021，shopId：1416699745771094656
        shopChannelMap.put("1242087450428572032", "Z104");
        shopChannelMap.put("1549253799779173120", "Z104");
        shopChannelMap.put("1416699745771094656", "Z142");
    }

    public List<SaleOrderImportInfo> importSaleOrder(String subWarehouseCode,
                                                     String saleSubChannel,
                                                     MultipartFile file) {

        List<SaleExcelModel> saleExcelModels = excelImportManager.transferClass(file, SaleExcelModel.class);
        List<MateInventoryQueryKeyInfo> keyList = new ArrayList<>();
        saleExcelModels.stream().forEach(
                m -> {
                    MateInventoryQueryKeyInfo keyInfo = new MateInventoryQueryKeyInfo();
                    keyInfo.setMateSku(m.getMateSkuCode());
                    keyInfo.setInventoryType(InventoryTypeEnum.ZP.getIntValue());
                    keyInfo.setPurchaseCode(m.getPurchaseCode());
                    keyInfo.setSubWarehouseCode(subWarehouseCode);
                    keyInfo.setSaleSubChannel(saleSubChannel);
                    keyList.add(keyInfo);
                }
        );
        List<MateInventoryDetailInfo> mateInventoryDetailInfos = mateInventoryFacade.listMateInventoryByKeyList(keyList);
        if (saleExcelModels.size() != mateInventoryDetailInfos.size()) {
            throw new BusinessException(OrderRespCode.MATE_SKU_EXCEL_IS_NOT_EXIST);
        }
        List<SaleOrderImportInfo> importInfos = saleExcelModels.stream().map(
                m -> {
                    SaleOrderImportInfo importInfo = new SaleOrderImportInfo();
                    importInfo.setSalePrice(m.getSalePrice());
                    importInfo.setOutQty(m.getOutQty());
                    mateInventoryDetailInfos.stream().filter(m1 -> StrUtil.equals(m.getMateSkuCode(), m1.getMateSku())).forEach(
                            m2 -> {
                                BeanUtil.copyProperties(m2, importInfo);
                            }
                    );
                    return importInfo;
                }
        ).collect(Collectors.toList());
        return importInfos;
    }


    /**
     * excel批量导入
     * => 销售单，和销售明细
     * => 出口单, 出口明细
     */
    public void saleAdd2(TocSaleImportLogInfo tocSaleImportLogInfo,
                         List<TocSaleImportLogDetailInfo> tocSaleImportLogDetailInfoList) {
        Map<String, List<TocSaleImportLogDetailInfo>> tocSaleImportLogDetailInfoMap = tocSaleImportLogDetailInfoList.stream()
                .collect(Collectors.groupingBy(TocSaleImportLogDetailInfo::getShopOrderNo));
        // 结算单内每个网店单号创建一条销售单
        for (Map.Entry<String, List<TocSaleImportLogDetailInfo>> tocSaleImportLogDetailInfoEntry : tocSaleImportLogDetailInfoMap.entrySet()) {
            String shopOrderNo = tocSaleImportLogDetailInfoEntry.getKey();
            List<TocSaleImportLogDetailInfo> list = tocSaleImportLogDetailInfoEntry.getValue();
            String subWarehouseCode = list.get(0).getSubWarehouseCode();
            String subWarehouseName = list.get(0).getSubWarehouseName();
            try {
                SaleOrderInfo saleOrderInfo = saleAdd2One(shopOrderNo, subWarehouseCode, subWarehouseName, tocSaleImportLogInfo, list);
                // 创建成功日志
                TocSaleImportJobLogAddRequest addRequest = new TocSaleImportJobLogAddRequest();
                addRequest.setLogId(tocSaleImportLogInfo.getId());
                addRequest.setShopOrderNo(shopOrderNo);
                addRequest.setIsSuccess(1);
                addRequest.setStatus(3);
                tocSaleImportJobLogFacade.add(addRequest);
            } catch (Exception e) {
                log.error("导入订单出库失败: " + shopOrderNo, e);
                // 创建失败日志
                TocSaleImportJobLogAddRequest addRequest = new TocSaleImportJobLogAddRequest();
                addRequest.setLogId(tocSaleImportLogInfo.getId());
                addRequest.setShopOrderNo(shopOrderNo);
                addRequest.setIsSuccess(0);
                addRequest.setStatus(1);
                addRequest.setFailReason(e.getMessage());
                tocSaleImportJobLogFacade.add(addRequest);
            }
        }
    }

    /**
     * 一条条处理, 按单号
     *
     * @param shopOrderNo
     * @param detailInfoList
     */
    public SaleOrderInfo saleAdd2One(String shopOrderNo, String subWarehouseCode, String subWarehouseName,
                                     TocSaleImportLogInfo tocSaleImportLogInfo,
                                     List<TocSaleImportLogDetailInfo> detailInfoList) {
        // 销售单，和销售明细
        SaleOrderAdd2Request request = new SaleOrderAdd2Request();
        SaleOrderInfo saleOrderInfo = new SaleOrderInfo();
        request.setSaleOrderInfo(saleOrderInfo);
        request.setItems(new ArrayList<>());
        saleOrderInfo.setOrderNo(idGenerator.xs());
        saleOrderInfo.setOrderType(SaleOrderOrderTypeEnum.T2.getIntValue());
        saleOrderInfo.setShopOrderNo(shopOrderNo);
        saleOrderInfo.setSaleChannel(tocSaleImportLogInfo.getSaleChannel());
        saleOrderInfo.setSaleSubChannel(tocSaleImportLogInfo.getSaleSubChannel());
        saleOrderInfo.setSubWarehouseCode(subWarehouseCode);
        saleOrderInfo.setSubWarehouseName(subWarehouseName);
        saleOrderInfo.setCreateUserCode(tocSaleImportLogInfo.getCreateUserCode());
        saleOrderInfo.setCreateUserName(tocSaleImportLogInfo.getCreateUserName());
        saleOrderInfo.setCurrencyCode(tocSaleImportLogInfo.getCurrencyCode());
        saleOrderInfo.setCurrencyName(tocSaleImportLogInfo.getCurrencyName());
        saleOrderInfo.setOrderTime(detailInfoList.get(0).getOrderTime());
        saleOrderInfo.setDeliveryTime(tocSaleImportLogInfo.getCreateTime());
        // 创建出库单
        MateInventoryOrderInfo mateInventoryOrderInfo = new MateInventoryOrderInfo();
        mateInventoryOrderInfo.setOrderNo(idGenerator.ck());
        mateInventoryOrderInfo.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
        mateInventoryOrderInfo.setBizType(MateInventoryOrderBizTypeEnum.T4.getIntValue());
        mateInventoryOrderInfo.setBizOrderNo(tocSaleImportLogInfo.getId().toString());
        mateInventoryOrderInfo.setSourceOrderType(SubjectEnum.T52.getCode());
        mateInventoryOrderInfo.setSubject(SubjectEnum.T52.getCode());
        mateInventoryOrderInfo.setSubWarehouseCode(subWarehouseCode);
        mateInventoryOrderInfo.setCreateUserCode(tocSaleImportLogInfo.getCreateUserCode());
        mateInventoryOrderInfo.setCreateUserName(tocSaleImportLogInfo.getCreateUserName());
        mateInventoryOrderInfo.setCreateTime(tocSaleImportLogInfo.getCreateTime());
        List<Object[]> objects = new ArrayList<>();
        Map<String, List<TocSaleImportLogDetailInfo>> detailMap =
                detailInfoList.stream().collect(Collectors.groupingBy(TocSaleImportLogDetailInfo::getMateSku));
        // 按商品分组，构建出库信息
        Map<String, List<MateInventoryInfo>> mateInventoryInfoMap = getMateInventoryInfoMap(
                detailInfoList.stream().map(detailInfo -> {
                    MateInventoryQueryKeyInfo keyInfo = new MateInventoryQueryKeyInfo();
                    keyInfo.setMateSku(detailInfo.getMateSku());
                    keyInfo.setInventoryType(InventoryTypeEnum.ZP.getIntValue());
                    keyInfo.setSubWarehouseCode(subWarehouseCode);
                    keyInfo.setSaleSubChannel(tocSaleImportLogInfo.getSaleSubChannel());
                    return keyInfo;
                }).collect(Collectors.toList()));
        List<MateInventoryDetailOrderInfo> mateInventoryDetailOrderInfoList = new ArrayList<>();
        for (Map.Entry<String, List<TocSaleImportLogDetailInfo>> entry : detailMap.entrySet()) {
            String mateSku = entry.getKey();
            List<TocSaleImportLogDetailInfo> list = entry.getValue();
            List<MateInventoryInfo> mateInventoryInfoList = mateInventoryInfoMap.get(mateSku);
            if (CollectionUtils.isEmpty(mateInventoryInfoList)) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "商品无库存，无法出库");
            }
            mateInventoryInfoList = sort(mateInventoryInfoList);
            int inventoryTotal = mateInventoryInfoList.stream().collect(Collectors.summingInt(MateInventoryInfo::getAvailableQty));
            int outTotal = list.stream().collect(Collectors.summingInt(TocSaleImportLogDetailInfo::getOutQty));
            if (outTotal > inventoryTotal) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "库存不足，无法出库");
            }
            for (TocSaleImportLogDetailInfo detailInfo : list) {
                int outQty = detailInfo.getOutQty();
                for (MateInventoryInfo mateInventoryInfo : mateInventoryInfoList) {
                    int inventoryQty = mateInventoryInfo.getAvailableQty();
                    if (inventoryQty == 0) {
                        continue;
                    }
                    MateInventoryDetailOrderInfo mateInventoryDetailOrderInfo;
                    if (outQty <= inventoryQty) {
                        mateInventoryDetailOrderInfo = buildMateInventoryDetailOrderInfo(
                                mateInventoryInfo, saleOrderInfo.getOrderNo(), outQty);
                        mateInventoryDetailOrderInfo.setCreateTime(tocSaleImportLogInfo.getCreateTime());
                        mateInventoryDetailOrderInfoList.add(mateInventoryDetailOrderInfo);
                        objects.add(new Object[]{detailInfo, mateInventoryDetailOrderInfo});
                        mateInventoryInfo.setAvailableQty(inventoryQty - outQty);
                        outQty = 0;
                        break;
                    } else {
                        mateInventoryDetailOrderInfo = buildMateInventoryDetailOrderInfo(
                                mateInventoryInfo, saleOrderInfo.getOrderNo(), inventoryQty);
                        mateInventoryDetailOrderInfo.setCreateTime(tocSaleImportLogInfo.getCreateTime());
                        mateInventoryDetailOrderInfoList.add(mateInventoryDetailOrderInfo);
                        objects.add(new Object[]{detailInfo, mateInventoryDetailOrderInfo});
                        mateInventoryInfo.setAvailableQty(0);
                        outQty = outQty - inventoryQty;
                    }
                }
            }
        }
        // 生成销售明细, 原一个商品会拆成多条销售明细
        for (Object[] array : objects) {
            TocSaleImportLogDetailInfo detailInfo = (TocSaleImportLogDetailInfo) array[0];
            MateInventoryDetailOrderInfo mateInventoryDetailOrderInfo = (MateInventoryDetailOrderInfo) array[1];
            SaleDetailOrderInfo saleDetailOrderInfo = new SaleDetailOrderInfo();
            saleDetailOrderInfo.setOrderNo(saleOrderInfo.getOrderNo());
            saleDetailOrderInfo.setDetailOrderNo(mateInventoryDetailOrderInfo.getSourceDetailOrderNo());
            saleDetailOrderInfo.setMateInventoryId(mateInventoryDetailOrderInfo.getMateInventoryId());
            saleDetailOrderInfo.setMateSku(mateInventoryDetailOrderInfo.getMateSku());
            saleDetailOrderInfo.setPurchaseCode(mateInventoryDetailOrderInfo.getPurchaseCode());
            saleDetailOrderInfo.setInventoryType(mateInventoryDetailOrderInfo.getInventoryType());
            saleDetailOrderInfo.setOutQty(mateInventoryDetailOrderInfo.getActualInQty());
            saleDetailOrderInfo.setProduceCode(mateInventoryDetailOrderInfo.getProduceCode());
            saleDetailOrderInfo.setPurchaseOrderNo(mateInventoryDetailOrderInfo.getPurchaseOrderNo());
            saleDetailOrderInfo.setPurchaseDetailOrderNo(mateInventoryDetailOrderInfo.getPurchaseDetailOrderNo());
            saleDetailOrderInfo.setCountryOfOrigin(mateInventoryDetailOrderInfo.getCountryOfOrigin());
            saleDetailOrderInfo.setSalePrice(detailInfo.getSalePriceWb());
            saleDetailOrderInfo.setSalePriceBb(detailInfo.getSalePrice());
            saleDetailOrderInfo.setMateCode(detailInfo.getMateCode());
            saleDetailOrderInfo.setMateName(detailInfo.getMateName());
            saleDetailOrderInfo.setMateSkuName(detailInfo.getMateSkuName());
            saleDetailOrderInfo.setGeneraCode(detailInfo.getGeneraCode());
            saleDetailOrderInfo.setGeneraCodeName(detailInfo.getGeneraCodeName());
            saleDetailOrderInfo.setMinorDefectsCode(detailInfo.getMinorDefectsCode());
            saleDetailOrderInfo.setMinorDefectsCodeName(detailInfo.getMinorDefectsCodeName());
            saleDetailOrderInfo.setSubclassCode(detailInfo.getSubclassCode());
            saleDetailOrderInfo.setSubclassCodeName(detailInfo.getSubclassCodeName());
            saleDetailOrderInfo.setCategoryName(detailInfo.getCategoryName());
            saleDetailOrderInfo.setBrandCode(detailInfo.getBrandCode());
            saleDetailOrderInfo.setBrandName(detailInfo.getBrandName());
            saleDetailOrderInfo.setInternationCode(detailInfo.getInternationCode());
            saleDetailOrderInfo.setUnitCode(detailInfo.getUnitCode());
            saleDetailOrderInfo.setUnitName(detailInfo.getUnitName());
            saleDetailOrderInfo.setProductSpecification(detailInfo.getProductSpecification());
            request.getItems().add(saleDetailOrderInfo);
        }
        MateInventoryOutRequest outRequest = new MateInventoryOutRequest();
        outRequest.setMateInventoryOrderInfo(mateInventoryOrderInfo);
        outRequest.setMateInventoryDetailOrderInfoList(mateInventoryDetailOrderInfoList);
        mateInventoryFacade.outMateInventory(outRequest);
        saleOrderFacade.createFinish(Lists.newArrayList(request));
        return saleOrderInfo;
    }

    private MateInventoryDetailOrderInfo buildMateInventoryDetailOrderInfo(MateInventoryInfo mateInventoryInfo, String orderNo, int qty) {
        MateInventoryDetailOrderInfo mateInventoryDetailOrderInfo = new MateInventoryDetailOrderInfo();
        mateInventoryDetailOrderInfo.setSourceOrderNo(orderNo);
        mateInventoryDetailOrderInfo.setSourceDetailOrderNo(idGenerator.xsetail());
        mateInventoryDetailOrderInfo.setActualInQty(qty);
        mateInventoryDetailOrderInfo.setMateInventoryId(mateInventoryInfo.getId());
        mateInventoryDetailOrderInfo.setMateSku(mateInventoryInfo.getMateSku());
        mateInventoryDetailOrderInfo.setInventoryType(mateInventoryInfo.getInventoryType());
        mateInventoryDetailOrderInfo.setSaleSubChannel(mateInventoryInfo.getSaleSubChannel());
        mateInventoryDetailOrderInfo.setPurchaseCode(mateInventoryInfo.getPurchaseCode());
        mateInventoryDetailOrderInfo.setProduceCode(mateInventoryInfo.getProduceCode());
        mateInventoryDetailOrderInfo.setCountryOfOrigin(mateInventoryInfo.getCountryOfOrigin());
        mateInventoryDetailOrderInfo.setProductDate(mateInventoryInfo.getProductDate());
        mateInventoryDetailOrderInfo.setExpireDate(mateInventoryInfo.getExpireDate());
        mateInventoryDetailOrderInfo.setPurchaseOrderNo(mateInventoryInfo.getPurchaseOrderNo());
        mateInventoryDetailOrderInfo.setPurchaseDetailOrderNo(mateInventoryInfo.getPurchaseDetailOrderNo());
        mateInventoryDetailOrderInfo.setCostPrice(mateInventoryInfo.getCostPrice());
        return mateInventoryDetailOrderInfo;
    }

    private Map<String, List<MateInventoryInfo>> getMateInventoryInfoMap(List<MateInventoryQueryKeyInfo> keyList) {
        List<MateInventoryDetailInfo> list = mateInventoryFacade.listMateInventoryByKeyList(keyList);
        return list.stream().collect(Collectors.groupingBy(MateInventoryInfo::getMateSku));
    }


    /**
     * 吉客云批量导入
     */
    public Pair<Boolean, String> saleAdd4(JkyTradeLogInfo jkyTradeLogInfo, List<JkyTradeLogDetailInfo> jkyTradeLogDetailInfoList) {
        // jky 币种转换，仓库转换
        Map<String, CurrencyInfo> currencyInfoMap = mdmComponent.queryCurrency();
        CurrencyInfo currencyInfo = null;
        for (Map.Entry<String, CurrencyInfo> stringCurrencyInfoEntry : currencyInfoMap.entrySet()) {
            if (stringCurrencyInfoEntry.getValue().getCode().equals(jkyTradeLogInfo.getChargeCurrency())) {
                currencyInfo = stringCurrencyInfoEntry.getValue();
                break;
            }
        }
        if (currencyInfo == null) {
            log.error("无法匹配的币种, {}", jkyTradeLogInfo.getTradeNo());
            return new Pair<>(false, "无法匹配的币种");
        }
        String saleSubChannel = shopChannelMap.get(jkyTradeLogInfo.getShopId());
        if (StringUtils.isBlank(saleSubChannel)) {
            log.error("未配置的渠道, {}", jkyTradeLogInfo.getTradeNo());
            return new Pair<>(false, "未配置的渠道");
        }
        Map<String, MateSkuInfo> mateSkuInfoMap = mdmComponent.queryMateSkuBySkuCodeList(jkyTradeLogDetailInfoList.stream()
                .map(JkyTradeLogDetailInfo::getMateSku).distinct().collect(Collectors.toList()));
        for (JkyTradeLogDetailInfo jkyTradeLogDetailInfo : jkyTradeLogDetailInfoList) {
            // 出库商品sku校验
            if (!mateSkuInfoMap.containsKey(jkyTradeLogDetailInfo.getMateSku())) {
                log.error("销售商品数据信息不存在, {}", jkyTradeLogInfo.getTradeNo());
                return new Pair<>(false, "销售商品数据信息不存在");
            }
        }
        List<SubWarehouseInfo> subWarehouseInfoList = subWarehouseFacade.listSubWarehouse();
        SubWarehouseInfo subWarehouseInfo = null;
        for (SubWarehouseInfo warehouseInfo : subWarehouseInfoList) {
            if (StringUtils.isNotBlank(warehouseInfo.getJkyWarehouseCode())
                    && warehouseInfo.getJkyWarehouseCode().contains(jkyTradeLogInfo.getWarehouseCode())) {
                subWarehouseInfo = warehouseInfo;
                break;
            }
        }
        if (subWarehouseInfo == null) {
            log.error("仓库信息不存在, {}", jkyTradeLogInfo.getTradeNo());
            return new Pair<>(false, "仓库信息不存在");
        }

        String subWarehouseCode = subWarehouseInfo.getSubWarehouseCode();
        String subWarehouseName = subWarehouseInfo.getSubWarehouseName();
        String currencyCode = currencyInfo.getCode();
        String currencyName = currencyInfo.getName();

        SaleOrderAdd2Request request = new SaleOrderAdd2Request();

        SaleOrderInfo saleOrderInfo = new SaleOrderInfo();
        request.setSaleOrderInfo(saleOrderInfo);
        request.setItems(new ArrayList<>());

        saleOrderInfo.setOrderNo(idGenerator.xs());
        saleOrderInfo.setOrderType(SaleOrderOrderTypeEnum.T4.getIntValue());
        saleOrderInfo.setPoOrderNo(jkyTradeLogInfo.getTradeNo());
        saleOrderInfo.setShopOrderNo(jkyTradeLogInfo.getOnlineTradeNo());
        try {
            if (StringUtils.isNotBlank(jkyTradeLogInfo.getConsignTime())) {
                saleOrderInfo.setDeliveryTime(DateUtil.parseDateTime(jkyTradeLogInfo.getConsignTime()));
            }
            if (StringUtils.isNotBlank(jkyTradeLogInfo.getTradeTime())) {
                saleOrderInfo.setOrderTime(DateUtil.parseDateTime(jkyTradeLogInfo.getTradeTime()));
            }
        } catch (Exception e) {
            log.error("日期转换错误{}", jkyTradeLogInfo.getTradeNo());
        }
        saleOrderInfo.setSubWarehouseCode(subWarehouseCode);
        saleOrderInfo.setSubWarehouseName(subWarehouseName);
        saleOrderInfo.setSaleChannel("平台");
        saleOrderInfo.setSaleSubChannel(saleSubChannel);
        saleOrderInfo.setCreateUserCode("system");
        saleOrderInfo.setCreateUserName("system");
        saleOrderInfo.setCurrencyCode(currencyCode);
        saleOrderInfo.setCurrencyName(currencyName);
        saleOrderInfo.setShopCode(jkyTradeLogInfo.getShopId());
        saleOrderInfo.setShopName(jkyTradeLogInfo.getShopName());
        // 创建出库单
        MateInventoryOrderInfo mateInventoryOrderInfo = new MateInventoryOrderInfo();
        mateInventoryOrderInfo.setOrderNo(idGenerator.ck());
        mateInventoryOrderInfo.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
        mateInventoryOrderInfo.setBizType(MateInventoryOrderBizTypeEnum.T5.getIntValue());
        mateInventoryOrderInfo.setBizOrderNo(jkyTradeLogInfo.getTradeNo());
        mateInventoryOrderInfo.setSourceOrderType(SubjectEnum.T92.getCode());
        mateInventoryOrderInfo.setSubject(SubjectEnum.T92.getCode());
        mateInventoryOrderInfo.setSubWarehouseCode(subWarehouseCode);
        mateInventoryOrderInfo.setCreateUserCode("system");
        mateInventoryOrderInfo.setCreateUserName("system");
        mateInventoryOrderInfo.setCreateTime(jkyTradeLogInfo.getCkTime());
        List<Object[]> objects = new ArrayList<>();
        Map<String, List<JkyTradeLogDetailInfo>> detailMap =
                jkyTradeLogDetailInfoList.stream().collect(Collectors.groupingBy(JkyTradeLogDetailInfo::getMateSku));
        // 按商品分组，构建出库信息
        Map<String, List<MateInventoryInfo>> mateInventoryInfoMap = getMateInventoryInfoMap(
                jkyTradeLogDetailInfoList.stream().map(detailInfo -> {
                    MateInventoryQueryKeyInfo keyInfo = new MateInventoryQueryKeyInfo();
                    keyInfo.setMateSku(detailInfo.getMateSku());
                    keyInfo.setInventoryType(InventoryTypeEnum.ZP.getIntValue());
                    keyInfo.setSubWarehouseCode(subWarehouseCode);
                    keyInfo.setSaleSubChannel(saleSubChannel);
                    return keyInfo;
                }).collect(Collectors.toList()));
        List<MateInventoryDetailOrderInfo> mateInventoryDetailOrderInfoList = new ArrayList<>();
        for (Map.Entry<String, List<JkyTradeLogDetailInfo>> entry : detailMap.entrySet()) {
            String mateSku = entry.getKey();
            List<JkyTradeLogDetailInfo> list = entry.getValue();
            List<MateInventoryInfo> mateInventoryInfoList = mateInventoryInfoMap.get(mateSku);
            if (CollectionUtils.isEmpty(mateInventoryInfoList)) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "商品无库存，无法出库");
            }
            mateInventoryInfoList = sort(mateInventoryInfoList);
            int inventoryTotal = mateInventoryInfoList.stream().collect(Collectors.summingInt(MateInventoryInfo::getAvailableQty));
            int outTotal = list.stream().collect(Collectors.summingInt(JkyTradeLogDetailInfo::getSellCount));
            if (outTotal > inventoryTotal) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "库存不足，无法出库");
            }
            for (JkyTradeLogDetailInfo detailInfo : list) {
                int outQty = detailInfo.getSellCount();
                for (MateInventoryInfo mateInventoryInfo : mateInventoryInfoList) {
                    int inventoryQty = mateInventoryInfo.getAvailableQty();
                    if (inventoryQty == 0) {
                        continue;
                    }
                    MateInventoryDetailOrderInfo mateInventoryDetailOrderInfo;
                    if (outQty <= inventoryQty) {
                        mateInventoryDetailOrderInfo = buildMateInventoryDetailOrderInfo(
                                mateInventoryInfo, saleOrderInfo.getOrderNo(), outQty);
                        mateInventoryDetailOrderInfo.setCreateTime(jkyTradeLogInfo.getCkTime());
                        mateInventoryDetailOrderInfoList.add(mateInventoryDetailOrderInfo);
                        objects.add(new Object[]{detailInfo, mateInventoryDetailOrderInfo});
                        mateInventoryInfo.setAvailableQty(inventoryQty - outQty);
                        outQty = 0;
                        break;
                    } else {
                        mateInventoryDetailOrderInfo = buildMateInventoryDetailOrderInfo(
                                mateInventoryInfo, saleOrderInfo.getOrderNo(), inventoryQty);
                        mateInventoryDetailOrderInfo.setCreateTime(jkyTradeLogInfo.getCkTime());
                        mateInventoryDetailOrderInfoList.add(mateInventoryDetailOrderInfo);
                        objects.add(new Object[]{detailInfo, mateInventoryDetailOrderInfo});
                        mateInventoryInfo.setAvailableQty(0);
                        outQty = outQty - inventoryQty;
                    }
                }
            }
        }

        // 生成销售明细, 原一个商品会拆成多条销售明细
        for (Object[] array : objects) {
            JkyTradeLogDetailInfo detailInfo = (JkyTradeLogDetailInfo) array[0];
            MateInventoryDetailOrderInfo mateInventoryDetailOrderInfo = (MateInventoryDetailOrderInfo) array[1];
            SaleDetailOrderInfo saleDetailOrderInfo = new SaleDetailOrderInfo();
            saleDetailOrderInfo.setOrderNo(saleOrderInfo.getOrderNo());
            saleDetailOrderInfo.setDetailOrderNo(mateInventoryDetailOrderInfo.getSourceDetailOrderNo());
            saleDetailOrderInfo.setMateInventoryId(mateInventoryDetailOrderInfo.getMateInventoryId());
            saleDetailOrderInfo.setMateSku(mateInventoryDetailOrderInfo.getMateSku());
            saleDetailOrderInfo.setPurchaseCode(mateInventoryDetailOrderInfo.getPurchaseCode());
            saleDetailOrderInfo.setInventoryType(mateInventoryDetailOrderInfo.getInventoryType());
            saleDetailOrderInfo.setOutQty(mateInventoryDetailOrderInfo.getActualInQty());
            saleDetailOrderInfo.setProduceCode(mateInventoryDetailOrderInfo.getProduceCode());
            saleDetailOrderInfo.setPurchaseOrderNo(mateInventoryDetailOrderInfo.getPurchaseOrderNo());
            saleDetailOrderInfo.setPurchaseDetailOrderNo(mateInventoryDetailOrderInfo.getPurchaseDetailOrderNo());
            saleDetailOrderInfo.setCountryOfOrigin(mateInventoryDetailOrderInfo.getCountryOfOrigin());
            saleDetailOrderInfo.setSalePrice(detailInfo.getSellPrice());
            saleDetailOrderInfo.setSalePriceBb(detailInfo.getSellPrice().multiply(currencyInfo.getUsdRate()).setScale(6, BigDecimal.ROUND_HALF_UP));
            saleDetailOrderInfo.setMateCode(detailInfo.getMateSku());
            MateSkuInfo mateSkuInfo = mateSkuInfoMap.get(detailInfo.getMateSku());
            saleDetailOrderInfo.setMateName(mateSkuInfo.getMateName());
            saleDetailOrderInfo.setMateSkuName(mateSkuInfo.getMateSkuName());
            saleDetailOrderInfo.setGeneraCode(mateSkuInfo.getGeneraCode());
            saleDetailOrderInfo.setGeneraCodeName(mateSkuInfo.getGeneraCodeName());
            saleDetailOrderInfo.setMinorDefectsCode(mateSkuInfo.getMinorDefectsCode());
            saleDetailOrderInfo.setMinorDefectsCodeName(mateSkuInfo.getMinorDefectsCodeName());
            saleDetailOrderInfo.setSubclassCode(mateSkuInfo.getSubclassCode());
            saleDetailOrderInfo.setSubclassCodeName(mateSkuInfo.getSubclassCodeName());
            saleDetailOrderInfo.setBrandCode(mateSkuInfo.getBrandCode());
            saleDetailOrderInfo.setBrandName(mateSkuInfo.getBrandName());
            saleDetailOrderInfo.setInternationCode(mateSkuInfo.getInternationCode());
            saleDetailOrderInfo.setUnitCode(mateSkuInfo.getUnitCode());
            saleDetailOrderInfo.setUnitName(mateSkuInfo.getUnitName());
            saleDetailOrderInfo.setProductSpecification(mateSkuInfo.getProductSpecification());
            request.getItems().add(saleDetailOrderInfo);
        }
        try {
            MateInventoryOutRequest outRequest = new MateInventoryOutRequest();
            outRequest.setMateInventoryOrderInfo(mateInventoryOrderInfo);
            outRequest.setMateInventoryDetailOrderInfoList(mateInventoryDetailOrderInfoList);
            mateInventoryFacade.outMateInventory(outRequest);
            saleOrderFacade.createFinish(Lists.newArrayList(request));
            return new Pair<>(true, "");
        } catch (Exception e) {
            log.error("销售单创建失败", e);
            return new Pair<>(true, "销售单创建失败");
        }
    }

    public void saleAdd1(TobSaleSettlementOrderInfo main, List<TobSaleSettlementDetailOrderInfo> item) {
        List<String> mateSku = CollUtil.getFieldValues(item, "mateSku", String.class);
        Map<String, MateSkuInfo> mateSkuInfoMap = mdmComponent.queryMateSkuBySkuCodeList(mateSku);
        Map<String, List<TobSaleSettlementDetailOrderInfo>> group = item.stream()
                .collect(Collectors.groupingBy(TobSaleSettlementDetailOrderInfo::getPoOrderNo));
        List<SaleOrderAdd2Request> addList = new ArrayList<>();
        for (Map.Entry<String, List<TobSaleSettlementDetailOrderInfo>> poGroup : group.entrySet()) {
            SaleOrderAdd2Request request = new SaleOrderAdd2Request();
            SaleOrderInfo saleOrderInfo = new SaleOrderInfo();
            String orderNo = idGenerator.xs();
            saleOrderInfo.setOrderNo(orderNo);
            saleOrderInfo.setOrderType(SaleOrderOrderTypeEnum.T1.getIntValue());
            saleOrderInfo.setOrderStatus(SaleOrderOrderStatusEnum.S3.getIntValue());
            saleOrderInfo.setSubWarehouseCode(null);
            saleOrderInfo.setSubWarehouseName(null);
            saleOrderInfo.setCreateUserCode(main.getCreateUserCode());
            saleOrderInfo.setCreateUserName(main.getCreateUserName());
            saleOrderInfo.setSaleChannel(main.getSaleChannel());
            saleOrderInfo.setSaleSubChannel(main.getSaleSubChannel());
            request.setSaleOrderInfo(saleOrderInfo);
            List<SaleDetailOrderInfo> detailOrderInfos = new ArrayList<>();
            for (TobSaleSettlementDetailOrderInfo tobSaleSettlementDetailOrderInfo : poGroup.getValue()) {
                SaleDetailOrderInfo saleDetailOrderInfo = new SaleDetailOrderInfo();
                saleDetailOrderInfo.setOrderNo(orderNo);
                saleDetailOrderInfo.setDetailOrderNo(idGenerator.xsetail());
                MateSkuInfo mateSkuInfo = mateSkuInfoMap.get(tobSaleSettlementDetailOrderInfo.getMateSku());
                saleDetailOrderInfo.setMateSku(mateSkuInfo.getMateSku());
                saleDetailOrderInfo.setInventoryType(InventoryTypeEnum.ZP.getIntValue());
                saleDetailOrderInfo.setOutQty(tobSaleSettlementDetailOrderInfo.getSettleQty());
                saleDetailOrderInfo.setSalePrice(tobSaleSettlementDetailOrderInfo.getSettlePrice());
                saleDetailOrderInfo.setMateCode(mateSkuInfo.getMateCode());
                saleDetailOrderInfo.setMateName(mateSkuInfo.getMateName());
                saleDetailOrderInfo.setMateSkuName(mateSkuInfo.getMateSkuName());
                saleDetailOrderInfo.setGeneraCode(mateSkuInfo.getGeneraCode());
                saleDetailOrderInfo.setGeneraCodeName(mateSkuInfo.getGeneraCodeName());
                saleDetailOrderInfo.setMinorDefectsCode(mateSkuInfo.getMinorDefectsCode());
                saleDetailOrderInfo.setMinorDefectsCodeName(mateSkuInfo.getMinorDefectsCodeName());
                saleDetailOrderInfo.setSubclassCode(mateSkuInfo.getSubclassCode());
                saleDetailOrderInfo.setSubclassCodeName(mateSkuInfo.getSubclassCodeName());
                saleDetailOrderInfo.setCategoryName(EthinkStrUtil.stitchStrings(mateSkuInfo.getGeneraCodeName(), mateSkuInfo.getMinorDefectsCodeName(), mateSkuInfo.getSubclassCodeName()));
                saleDetailOrderInfo.setBrandCode(mateSkuInfo.getBrandCode());
                saleDetailOrderInfo.setBrandName(mateSkuInfo.getBrandName());
                saleDetailOrderInfo.setInternationCode(mateSkuInfo.getInternationCode());
                saleDetailOrderInfo.setUnitCode(mateSkuInfo.getUnitCode());
                saleDetailOrderInfo.setUnitName(mateSkuInfo.getUnitName());
                saleDetailOrderInfo.setProductSpecification(mateSkuInfo.getProductSpecification());
                saleDetailOrderInfo.setCountryOfOrigin(mateSkuInfo.getCountryOfOrigin());
                detailOrderInfos.add(saleDetailOrderInfo);
            }
            request.setItems(detailOrderInfos);
            addList.add(request);
        }
        saleOrderFacade.createFinish(addList);
    }

    public void saleApply(List<SaleDetailOrderModel> saleDetailOrderInfoList) {
        // 销售单提交后，冻结库存，
        List<MateInventoryLockLogAddRequest> requests = new ArrayList<>();
        for (SaleDetailOrderInfo saleDetailOrderInfo : saleDetailOrderInfoList) {
            MateInventoryLockLogAddRequest mateInventoryLockLogAddRequest = new MateInventoryLockLogAddRequest();
            mateInventoryLockLogAddRequest.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
            mateInventoryLockLogAddRequest.setSourceOrderNo(saleDetailOrderInfo.getOrderNo());
            mateInventoryLockLogAddRequest.setSourceDetailOrderNo(saleDetailOrderInfo.getDetailOrderNo());
            mateInventoryLockLogAddRequest.setSourceOrderType(SubjectEnum.T72.getCode());
            mateInventoryLockLogAddRequest.setSubject(SubjectEnum.T72.getCode());
            mateInventoryLockLogAddRequest.setMateInventoryId(saleDetailOrderInfo.getMateInventoryId());
            mateInventoryLockLogAddRequest.setLockQty(saleDetailOrderInfo.getOutQty());
            requests.add(mateInventoryLockLogAddRequest);
        }
        mateInventoryFacade.lockMateInventory(requests);
    }

    public void saleApplyPass(SaleOrderInfo orderInfo, List<SaleDetailOrderModel> saleDetailOrderModelList) {
        LogisticsTraceApplyAddRequest addRequest = new LogisticsTraceApplyAddRequest();
        addRequest.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
        addRequest.setSourceOrderNo(orderInfo.getOrderNo());
        addRequest.setSourceOrderType(SubjectEnum.T72.getCode());
        addRequest.setSubject(SubjectEnum.T72.getCode());
        addRequest.setCreateUserCode(orderInfo.getCreateUserCode());
        addRequest.setCreateUserName(orderInfo.getCreateUserName());
        addRequest.setCompanyCode(orderInfo.getCustomerCode());
        addRequest.setCompanyName(orderInfo.getCustomerName());
        addRequest.setLock(false);
        addRequest.setSaleCkItems(saleDetailOrderModelList.stream().map(detailInfo -> {
            LogisticsTraceApplyAddRequest.SaleCkItem saleCkItem = new LogisticsTraceApplyAddRequest.SaleCkItem();
            saleCkItem.setSourceDetailOrderNo(detailInfo.getDetailOrderNo());
            saleCkItem.setMateInventoryId(detailInfo.getMateInventoryId());
            saleCkItem.setApplyInQty(detailInfo.getOutQty());
            return saleCkItem;
        }).collect(Collectors.toList()));
        logisticsTraceApplyOrderFacade.addLogisticsTraceApplyOrder(addRequest);
    }

    private static List<MateInventoryInfo> sort(List<MateInventoryInfo> mateInventoryInfoList) {
        return mateInventoryInfoList.stream()
                .sorted((a, b) -> {
                    if (a == null && b != null) {
                        return -1;
                    }
                    if (a != null && b == null) {
                        return 1;
                    }
                    if (a == null && b == null) {
                        return 0;
                    }
                    if (a.getProductDate() == null && b.getProductDate() != null) {
                        return -1;
                    }
                    if (a.getProductDate() != null && b.getProductDate() == null) {
                        return 1;
                    }
                    if (a.getProductDate() == null && b.getProductDate() == null) {
                        return 0;
                    }
                    return a.getProductDate().compareTo(b.getProductDate());
                }).collect(Collectors.toList());
    }

    public void saleOrderRelease(List<SaleDetailOrderInfo> saleDetailOrderInfoList) {
        // 审批拒绝,释放库存
        List<MateInventoryLockLogAddRequest> requests = new ArrayList<>();
        for (SaleDetailOrderInfo saleDetailOrderInfo : saleDetailOrderInfoList) {
            MateInventoryLockLogAddRequest mateInventoryLockLogAddRequest = new MateInventoryLockLogAddRequest();
            mateInventoryLockLogAddRequest.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
            mateInventoryLockLogAddRequest.setSourceOrderNo(saleDetailOrderInfo.getOrderNo());
            mateInventoryLockLogAddRequest.setSourceDetailOrderNo(saleDetailOrderInfo.getDetailOrderNo());
            mateInventoryLockLogAddRequest.setSourceOrderType(SubjectEnum.T72.getCode());
            mateInventoryLockLogAddRequest.setSubject(SubjectEnum.T72.getCode());
            mateInventoryLockLogAddRequest.setMateInventoryId(saleDetailOrderInfo.getMateInventoryId());
            mateInventoryLockLogAddRequest.setLockQty(saleDetailOrderInfo.getOutQty());
            requests.add(mateInventoryLockLogAddRequest);
        }
        mateInventoryFacade.releaseLockMateInventory(requests);
    }

}
